package org.esti.controller;

import org.esti.model.User;
import org.esti.model.utils.LevelPropertyEditor;
import org.esti.service.LevelService;
import org.esti.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import javax.validation.Valid;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author Artem Loginov (logart)
 */

/**
 * This controller is used for providing mapping between request and view,
 * getKnowledgeFieldById registration and provide validity of it.
 */
@Controller
@RequestMapping("/registration")
public class RegistrationController {

    private static final String ERROR_VIEW_NAME = "registration";

    @Autowired
    private UserService userService;

    @Autowired
    private LevelService levelService;
    private static final Logger LOGGER = Logger.getLogger(RegistrationController.class.getName());

    /**
     * Sets up data binder to bind specific data type such as Level
     *
     * @param binder in this binder method will register custom property editors
     *               to achieve data binding of specific types
     * @see Level
     *      or Date in specific format
     */
    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat("dd/MM/yyyy"), true);
        binder.registerCustomEditor(Date.class, editor);
        binder.registerCustomEditor(org.esti.model.Level.class, new LevelPropertyEditor(levelService));
    }

    /**
     * Shows registration form
     *
     * @param model set of parameters which will be passed to view. In this case user and list of all professional levels.
     * @return name of view which will be render
     */
    @RequestMapping(value = "", method = RequestMethod.GET)
    public String showRegistrationForm(Model model) {
        model.addAttribute(new User());
        model.addAttribute("levels", levelService.getAvailableLevels());
        return "registration";
    }

    /**
     * Get user and it's field from form and provide validation of user.
     * After that method call creating user in db and redirect to user profile if creation was success.
     *
     * @param password      second password to validate password in user object.
     * @param user          which can be validated and after that stored in database
     * @param bindingResult result of converting form data to user field. This object contain validation errors
     * @param model         set of parameters which will be passed to view.
     * @return name of view which will be render
     */
    @RequestMapping(method = RequestMethod.POST)
    public String getUserInfoFromRegistrationForm(
            @RequestParam(value = "password2", required = true) String password,
            @Valid User user,
            BindingResult bindingResult,
            Model model) {

        model.addAttribute("levels", levelService.getAvailableLevels());

        if (bindingResult.hasErrors()) {
            LOGGER.log(Level.INFO, "registration form is not valid");
            for (ObjectError error : bindingResult.getAllErrors()) {
                LOGGER.log(Level.INFO, "There is error : " + error.getDefaultMessage() + " in object : " + error.getObjectName());
            }

            for (FieldError error : bindingResult.getFieldErrors()) {
                LOGGER.log(Level.INFO, "There is error : " + error.getDefaultMessage() + " in field : " + error.getField());
            }

            return ERROR_VIEW_NAME;
        }


        if (!password.equals(user.getPassword())) {
            FieldError error = new FieldError("user", "password", "Passwords must be equal");
            bindingResult.addError(error);
            LOGGER.log(Level.INFO, "passwords is not match");
            return ERROR_VIEW_NAME;
        }

        if (userService.isUserExist(user)) {
            ObjectError error = new ObjectError(
                    "user",
                    "user with login " + user.getLogin() + " already exist");
            bindingResult.addError(error);
            return ERROR_VIEW_NAME;
        } else {
            userService.createUser(user);
        }


        return "redirect:/" + user.getLogin() + "/profile?first_login=true";
    }

}
